/*
 * This file is part of finding-duplicates.
 *
 * finding-duplicates is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * finding-duplicates is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with finding-duplicates.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.xemantic.duplicates;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Class which performs benchmarks on methods of {@link Algorithms} class.
 * <p>
 * Created on Jul 12, 2008
 *
 * @author hshsce
 * @version $Id$
 */
public class BenchmarkRunner {

	private static final int MAX_ELEMENT_COUNT = 8;

	private final List<Permutator> m_permutators = new ArrayList<Permutator>();

	public static void main(final String[] args) {
		System.out.println("Checking algorithm output and data integrity");
		(new Permutator("sanity check permutator", MAX_ELEMENT_COUNT) {
			final Set<Boolean> m_results = new HashSet<Boolean>();
			@Override
			protected void handle(final int[] a) {
				final int[] copy = Arrays.copyOf(a, a.length);
				add(Algorithms.checkDuplicatesHistogram(copy), a, copy);
				add(Algorithms.checkDuplicatesBitSet(copy), a, copy);
				add(Algorithms.checkDuplicatesHashSet(copy), a, copy);
				add(Algorithms.checkDuplicatesTreeSet(copy), a, copy);
				add(Algorithms.checkDuplicatesModulo(copy), a, copy);
				add(Algorithms.checkDuplicatesModuloOptimized(copy), a, copy);
				add(Algorithms.checkDuplicatesSum(copy), a, copy);
				add(Algorithms.checkDuplicatesPowers(copy), a, copy);
				add(Algorithms.checkDuplicatesPowersOptimized(copy), a, copy);
				add(Algorithms.checkDuplicatesSign(copy), a, copy);
				add(Algorithms.checkDuplicatesHighestBit(copy), a, copy);

				if (m_results.size() != 1) {
					System.out.println(Arrays.toString(a));
					throw new AssertionError();
				}
				m_results.clear();
			}
			private void add(final boolean result, final int[] expected, final int[] actual) {
				m_results.add(result);
				if (!Arrays.equals(expected, actual)) {
					throw new AssertionError();
				}
			}

		}).run();

		final BenchmarkRunner runner = new BenchmarkRunner();
		runner.add(new Permutator("Histogram", MAX_ELEMENT_COUNT) {
			@Override
			public void handle(final int[] a) {
				Algorithms.checkDuplicatesHistogram(a);
			}
		});
		runner.add(new Permutator("BitSet", MAX_ELEMENT_COUNT) {
			@Override
			public void handle(final int[] a) {
				Algorithms.checkDuplicatesBitSet(a);
			}
		});
		runner.add(new Permutator("HashSet", MAX_ELEMENT_COUNT) {
			@Override
			public void handle(final int[] a) {
				Algorithms.checkDuplicatesHashSet(a);
			}
		});
		runner.add(new Permutator("TreeSet", MAX_ELEMENT_COUNT) {
			@Override
			public void handle(final int[] a) {
				Algorithms.checkDuplicatesTreeSet(a);
			}
		});
		runner.add(new Permutator("Modulo", MAX_ELEMENT_COUNT) {
			@Override
			public void handle(final int[] a) {
				Algorithms.checkDuplicatesModulo(a);
			}
		});
		runner.add(new Permutator("Modulo opt.", MAX_ELEMENT_COUNT) {
			@Override
			public void handle(final int[] a) {
				Algorithms.checkDuplicatesModuloOptimized(a);
			}
		});
		runner.add(new Permutator("Sum", MAX_ELEMENT_COUNT) {
			@Override
			public void handle(final int[] a) {
				Algorithms.checkDuplicatesSum(a);
			}
		});
		runner.add(new Permutator("Powers", MAX_ELEMENT_COUNT) {
			@Override
			public void handle(final int[] a) {
				Algorithms.checkDuplicatesPowers(a);
			}
		});
		runner.add(new Permutator("Powers opt.", MAX_ELEMENT_COUNT) {
			@Override
			public void handle(final int[] a) {
				Algorithms.checkDuplicatesPowersOptimized(a);
			}
		});
		runner.add(new Permutator("Sign", MAX_ELEMENT_COUNT) {
			@Override
			public void handle(final int[] a) {
				Algorithms.checkDuplicatesSign(a);
			}
		});
		runner.add(new Permutator("Highest bit", MAX_ELEMENT_COUNT) {
			@Override
			public void handle(final int[] a) {
				Algorithms.checkDuplicatesHighestBit(a);
			}
		});

		runner.runTests();
		runner.printResults();
	}

	public void add(final Permutator permutator) {
		m_permutators.add(permutator);
	}

	public void runTests() {
		for (final Permutator permutator : m_permutators) {
			permutator.run();
		}
	}

	public void printResults() {
		int maxLength = 0;
		for (final Permutator permutator : m_permutators) {
			final int length = permutator.getName().length();
			if (length > maxLength) {
				maxLength = length;
			}
		}
		for (final Permutator permutator : m_permutators) {
			final String name = permutator.getName();
			System.out.println(padLeft(name, maxLength) + ": " + permutator.getDuration());
		}
	}

	private String padLeft(final String value, final int size) {
		final char[] padding = new char[size - value.length()];
		Arrays.fill(padding, ' ');
		return (new StringBuilder(value)).append(padding).toString();
	}

}
